package cn.com.sbell.vss.auth.radius;

import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import net.sourceforge.jradiusclient.RadiusAttribute;
import net.sourceforge.jradiusclient.RadiusAttributeValues;
import net.sourceforge.jradiusclient.RadiusClient;
import net.sourceforge.jradiusclient.RadiusPacket;
import net.sourceforge.jradiusclient.attributes.VendorSpecificAttribute;
import net.sourceforge.jradiusclient.exception.RadiusException;
import net.sourceforge.jradiusclient.packets.PapAccessRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import cn.com.sbell.vss.VssConstants;
import cn.com.sbell.vss.VssException;

public class VssRadiusClient {
	private static final Log log = LogFactory.getLog(VssRadiusClient.class);

	private int timeout = 6000;

	private int retries = 2;

	private List radiusServerInfo = new Vector();

	public RadiusPacket authenticate(RadiusPacket accessRequest) {
		for (int i = 0; i < radiusServerInfo.size(); i++) {
			try {
				RadiusServerInfo server = (RadiusServerInfo) radiusServerInfo
						.get(i);

				if (server == null) {
					System.out.println("Radius server is null");
					if(log.isWarnEnabled()){
					log.warn("Radius server is null");
					}
					continue;
				}
				if (log.isDebugEnabled()) {
					System.out.println("Connecting to " + server.getHost() + ":"
							+ server.getAuthport() + "   with shared secret "
							+ server.getSharedSecret());
					log.debug("Connecting to " + server.getHost() + ":"
							+ server.getAuthport() + "   with shared secret "
							+ server.getSharedSecret());
				}
				RadiusClient client = new RadiusClient(server.getHost(), server
						.getAuthport(), server.getAcctport(), server
						.getSharedSecret(), timeout);
				System.out.println(client);
				RadiusPacket rp = client.authenticate(accessRequest, retries);
				System.out.println(rp);
				if (i > 0) {
					radiusServerInfo.add(0, server);
					radiusServerInfo.remove(i + 1);
				}
				return rp;
			} catch (RadiusException ex) {
				if(log.isWarnEnabled()){
				log.warn("RadiusException", ex);
				}
			} catch (InvalidParameterException ex) {
				if(log.isWarnEnabled()){
				log.warn("InvalidParameterException", ex);
				}
			} catch (IndexOutOfBoundsException ex) {
				if(log.isWarnEnabled()){
				log.warn("IndexOutOfBoundsException", ex);
				}
			} catch (Throwable ex) {
				if(log.isWarnEnabled()){
				log.warn("Exception", ex);
				}
			}
			if(log.isDebugEnabled()){
			log.debug("retrying ...");
			}
		}
		return null;
	}

	public void addRadiusServer(RadiusServerInfo s) {
		radiusServerInfo.add(s);
	}

	public void setRadiusServerInfo(List radiusServerInfo) {
		this.radiusServerInfo = radiusServerInfo;
	}

	public void setRetries(int retries) {
		this.retries = retries;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	public static void main(String[] args) {
		VssRadiusClient client = new VssRadiusClient();
		RadiusServerInfo info = new RadiusServerInfo();
		info.setHost("192.168.6.75");
		info.setSharedSecret("12345678");
		List list = new ArrayList();
		list.add(info);
		client.setRadiusServerInfo(list);

		String username = "root";
		try {
			PapAccessRequest accessRequest = new PapAccessRequest(username, "123456");
			accessRequest.setAttribute(new RadiusAttribute(
					RadiusAttributeValues.NAS_IP_ADDRESS, 
//					AuthenticatedByRadius //changed by vondart
					RadiusAuthenticate
							.getIpBytes("192.168.6.75",log)));
			accessRequest.setAttribute(new VendorSpecificAttribute(
					RadiusAuthenticate.VISS_NAS_TYPE, new byte[] { 0, 0, 0,
							(byte) 1 }));

			RadiusPacket accessResponse = client.authenticate(accessRequest);
			switch (accessResponse.getPacketType()) {
			case RadiusPacket.ACCESS_ACCEPT:
				if(log.isDebugEnabled()){
				log.debug("User " + username + " authenticated");
				}
				// sessionHolder.setSessionTimeout(accessRequest.getAttribute(
				// RadiusAttributeValues.SESSION_TIMEOUT).getIntValue());
				break;
			case RadiusPacket.ACCESS_REJECT:
				if(log.isDebugEnabled()){
				log.debug("User " + username + " NOT authenticated");
				}
				throw new VssException(VssConstants.CODE_AUTHENTICATION_FAILED);
			case RadiusPacket.ACCESS_CHALLENGE:
				String reply = new String(accessResponse.getAttribute(
						RadiusAttributeValues.REPLY_MESSAGE).getValue());
				if(log.isDebugEnabled()){
				log.debug("User " + username + " Challenged with " + reply);
				}
				throw new VssException(VssConstants.CODE_AUTHENTICATION_FAILED);
			default:
				if(log.isDebugEnabled()){
				log.debug("Whoa, what kind of RadiusPacket is this "
						+ accessResponse.getPacketType());
				}
				throw new VssException(VssConstants.CODE_AUTHENTICATION_FAILED);
			}
		} catch (Throwable e) {
			throw new VssException(VssConstants.CODE_AUTHENTICATION_FAILED);
		}
	}
}
